package cn.lei.netty.herostory.login;

import cn.lei.netty.herostory.MySqlSessionFactory;
import cn.lei.netty.herostory.async.AsyncOperationProcessor;
import cn.lei.netty.herostory.async.IAsyncOperation;
import cn.lei.netty.herostory.login.db.IUserDao;
import cn.lei.netty.herostory.login.db.UserEntity;
import cn.lei.netty.herostory.util.RedisUtil;
import com.alibaba.fastjson.JSONObject;
import org.apache.ibatis.session.SqlSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;

import java.util.function.Function;

/**
 * 登录服务
 *
 * @author lei
 */
public final class LoginService {
    /**
     * 日志服务
     */
    static private final Logger LOGGER = LoggerFactory.getLogger(LoginService.class);

    /**
     * 单例对象
     */
    private static final LoginService INSTANCE = new LoginService();

    /**
     * 私有化默认构造器
     */
    private LoginService() {
    }

    /**
     * 获取单例对象
     *
     * @return
     */
    public static LoginService getInstance() {
        return INSTANCE;
    }


    public void userLogin(String userName, String password, Function<UserEntity, Void> callBack) {
        if (userName == null || password == null) {
            return;
        }
        AsyncGetUserEntity asyncOp = new AsyncGetUserEntity(userName, password) {
            @Override
            public int getBindId() {
                return userName.charAt(userName.length() - 1);
            }

            @Override
            public void doFinish() {
                if (callBack != null) {
                    callBack.apply(this.getUserEntity());
                }
            }
        };
        AsyncOperationProcessor.getInstance().process(asyncOp);
    }

    /**
     * 更新 Redis 中的用户基本信息
     *
     * @param userEntity 用户实体
     */
    private void updateBasicInfoInRedis(UserEntity userEntity) {
        if (null == userEntity) {
            return;
        }

        try (Jedis redis = RedisUtil.getJedis()) {
            JSONObject jsonObj = new JSONObject();
            jsonObj.put("userName", userEntity.userName);
            jsonObj.put("heroAvatar", userEntity.heroAvatar);

            redis.hset("User_" + userEntity.userId, "BasicInfo", jsonObj.toJSONString());
        } catch (Exception ex) {
            // 记录错误日志
            LOGGER.error(ex.getMessage(), ex);
        }
    }

    /**
     * 异步方式获取用户实体
     */
    private class AsyncGetUserEntity implements IAsyncOperation {
        /**
         * 用户名称
         */
        private final String userName;

        /**
         * 密码
         */
        private final String password;

        /**
         * 用户实体
         */
        private UserEntity userEntity;

        /**
         * 类参数构造器
         *
         * @param userName 用户名称
         * @param password 密码
         */
        AsyncGetUserEntity(String userName, String password) {
            this.userName = userName;
            this.password = password;
        }

        /**
         * 获取用户实体
         *
         * @return 用户实体
         */
        UserEntity getUserEntity() {
            return userEntity;
        }

        @Override
        public void doAsync() {
            try (SqlSession mysqlSession = MySqlSessionFactory.openSession()) {
                //获取DAO
                IUserDao dao = mysqlSession.getMapper(IUserDao.class);

                //获取用户实体
                UserEntity userEntity = dao.getByUserName(userName);

                LOGGER.info("当前线程 = {}", Thread.currentThread().getName());

                //不为空则校验密码,为空则直接创建新用户
                if (userEntity != null) {
                    if (!password.equals(userEntity.password)) {
                        throw new RuntimeException("密码错误");
                    }
                } else {
                    userEntity = new UserEntity();
                    userEntity.userName = userName;
                    userEntity.password = password;
                    userEntity.heroAvatar = "Hero_Shaman";
                    dao.insertInto(userEntity);
                }
                //更新redis
                LoginService.getInstance().updateBasicInfoInRedis(userEntity);

                this.userEntity = userEntity;
            } catch (Exception ex) {
                LOGGER.info(ex.getMessage(), ex);
            }
        }

        @Override
        public void doFinish() {
            IAsyncOperation.super.doFinish();
        }
    }

}
